<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app"> 
        工资:<input type="text" v-model="salary" /><span>{{ salary }}</span>
        <br /> 
        奖金:<input type="text" v-model="bonus" /><span v-text="bonus"> </span> 
         <br /> 
         <span>到手:{{ cTotalMoney }}</span> 
         <button @click="hDobule">工资加倍</button> 
    </div>
    <script>
        // 设置监察者模式
        function TargetObject() {
            this.watcherList = []
        }
        TargetObject.prototype.add = function (watch) {
            this.watcherList.push(watch)
        }
        TargetObject.prototype.notify = function () {
            this.watcherList.forEach(watch => watch.update())
        }
        function watcher(vm,exp,fn){
            TargetObject.watcher = this, // 给TargetObject添加watcher属性,并将当前实例赋值给他
            vm[exp], // exp是属性值, 进入到get方法中,访问一下 判断TargetObject.watcher,然后进行 就会将watcehr实例添加list中
            TargetObject.watcher = null, // 避免重复添加watcher
            this.fn = fn
        }
        
        watcher.prototype.update = function () {
            console.log(`观察者${this.name} 被调用了`)
            this.fn()
        }
        var to = new TargetObject()
        to.notify()
        // 数据劫持(使用原型的方式)
        MVVM.prototype.observe = function(obj) {
            Object.keys(obj).forEach(key => {
                var val = obj[key]
                let to = new TargetObject()
                // 将data中的数据直接挂载到this也就是vm上
                Object.defineProperty(this,key,{
                    set: function(newVal){
                        console.log(`${val}---->${newVal}`)
                        val = newVal
                        to.notify()
                    },
                    get: function() {
                        if (TargetObject.watcher) {
                            to.add(TargetObject.watcher)
                        }
                        console.log('get获取的方式' + val)
                        return val
                    }
                })
            })
        }
        // 编译模板部分
        MVVM.prototype.compile = function () {
            let el = this.$el
            // 正则匹配两个花括号
            let regMustache = /{{(.*)}}/
            Array.from(el.children).forEach(node => {
                // 找到v-model 
                if(node.hasAttribute('v-model')){
                    let attributeVal = node.getAttribute('v-model')
                    node.value = this[attributeVal]
                    new watcher(this,attributeVal,()=>{
                        node.value = this[attributeVal]
                    })
                    node.addEventListener('input',e => {
                        this[attributeVal] = e.target.value
                    })
                }
                // 找到v-text
                if(node.hasAttribute('v-text')){
                    let attributeVal = node.getAttribute('v-text')
                    node.innerHTML = this[attributeVal]
                    new watcher(this,attributeVal,()=>{
                        node.innerHTML = this[attributeVal]
                    })
                }
                // 找到@click
                if(node.hasAttribute('@click')){
                    let attributeVal = node.getAttribute('@click')
                    node.addEventListener('click',() => {
                        vm.$methods[attributeVal]()
                    })
                }
                if(regMustache.test(node.innerHTML)){
                    node._intervalInnerHTML = node.innerHTML
                    let _t = node.innerHTML.replace(/\s/g,"").match(regMustache)
                    let exp = _t[1]
                    console.log(exp);
                    node.innerHTML = node._intervalInnerHTML.replace(regMustache,this[exp])
                    new watcher(this,exp,()=>{
                        node.innerHTML = node._intervalInnerHTML.replace(regMustache,this[exp])
                    })
                }
            })
        }
        var vm = new MVVM({
            data: {
                salary: 10000,
                bonus: 50000
            },
            method:{
                hDobule() {
                    console.log('点击了加倍');
                }
            }
        })
        function MVVM(options) {
            // 将data直接绑定在vm上
            this.$data = options.data
            this.$methods = options.method
            // 获取渲染区域的dom对象
            this.$el = document.querySelector('#app')
            // 设置监察者
            this.observe(this.$data)
            // 编译者
            this.compile()
        }
    </script>
</body>
</html>